import threading
import time
import typing

class TimerThread(threading.Thread):
    def __init__(
        self,
        period: 'int') -> None:
        super().__init__(None, None, None, [], None, daemon=True)
        self.period = max(period * 0.001, 0.01) - 0.003   # 循环周期
        self._functionTable = dict()                      # 存放函数的表
        self._isRunning = False                           # 本线程是否在运行
        self._lock = threading.Lock()
    
    def AddFunction(self, task_name: 'str', function: typing.Callable[[], None]) -> None:
        '''
        添加一个定时任务
        '''
        # uuid_ = uuid.uuid4().hex
        try:
            self._lock.acquire()
            self._functionTable[task_name] = function
        finally:
            self._lock.release()
        # return uuid_

    def RemoveFunction(self, task_name: 'str') -> None:
        '''
        根据 uuid 移除一个定时任务
        '''
        if (not task_name in self._functionTable.keys()):
            return
        try:
            self._lock.acquire()
            del self._functionTable[task_name]
        finally:
            self._lock.release()

    def run(self) -> None:
        # return super().run()
        '''
        实际运行的函数
        '''
        self._isRunning = True
        while (True):
            # print('线程周期 {0} 进入一次执行'.format(self.period))
            if (self._isRunning):
                if (len(self._functionTable) == 0):
                    break
                try:
                    self._lock.acquire()
                    for func_ in self._functionTable.values():
                        func_()
                finally:
                    self._lock.release()
                # print('线程周期 {0} 开始等待'.format(self.period))
                # QThread.msleep(self.period - 3)
                # print('线程周期 {0} 等待结束'.format(self.period))
                time.sleep(self.period)
            else:
                break

    def Stop(self) -> None:
        '''
        停止本线程
        '''
        self._isRunning = False
            



class PyTimerScheduler(object):
    '''
    一个定时调用调度的函数库
    '''
    def __init__(self) -> None:
        self._periodMapThread = dict()      # 线程列表
        self._taskNameMapThread = dict()        # 任务名称 map 到Thread的表

    def Start(self) -> None:
        '''
        启动时间调度
        '''
        for thread_ in self._taskNameMapThread.values():
            if (not isinstance(thread_, TimerThread)):
                continue
            if (not thread_.is_alive()):
                thread_.start()

    def Stop(self) -> None:
        '''
        结束时间调度
        '''
        for thread_ in self._taskNameMapThread.values():
            if (not isinstance(thread_, TimerThread)):
                continue
            thread_.Stop()
            # if (thread_.is_alive()):
            #     thread_.terminate()

    def AddTask(self, task_name: 'str', ms_period: 'int', task: typing.Callable) -> None:
        '''
        添加一个定时任务
        '''
        timer_thread_ = self._periodMapThread.get(ms_period, None)
        if (isinstance (timer_thread_, TimerThread)):
            # 如果已经有一个定时线程, 就在该线程成添加任务
            timer_thread_.AddFunction(task_name, task)
            if (not timer_thread_.is_alive()):
                # timer_thread_.start(QThread.TimeCriticalPriority)
                timer_thread_.start()
            self._taskNameMapThread[task_name] = timer_thread_
        elif (timer_thread_ == None):
            thread_ = TimerThread(ms_period)
            # thread_
            thread_.AddFunction(task_name, task)
            # thread_.start(QThread.TimeCriticalPriority)
            thread_.start()
            self._periodMapThread[ms_period] = thread_
            self._taskNameMapThread[task_name] = thread_

    def RemoveTask(self, task_name: 'str') -> None:
        '''
        移除一个定时任务
        '''
        thread_ = self._taskNameMapThread.get(task_name, None)
        if (not isinstance(thread_, TimerThread)):
            return
        thread_.RemoveFunction(task_name)
        if (not task_name in self._taskNameMapThread.keys()):
            return
        del self._taskNameMapThread[task_name]

    def GetPeriod(self, task_name: 'str') -> 'int':
        '''
        获取指定任务名称的周期，单位为ms
        '''
        thread_ = self._taskNameMapThread.get(task_name, None)
        if (not isinstance(thread_, TimerThread)):
            return 0
        return int(thread_.period * 1000)

    def Clear(self) -> None:
        '''
        清除所有定时任务
        '''
        self.Stop()
        self._taskNameMapThread.clear()
        self._periodMapThread.clear()

